use std::{collections::HashMap, sync::{Arc, Mutex}};

use once_cell::sync::Lazy;

use crate::rtda::{Object, object::DataType};

use super::{ClassLoader, Class};

// *mut Object 通过讲*mut Object 转换为usize存储在hashmap中, 
// 获取时通过std::mem::transmute() 转换为*mut Object， 不确定通过此方法是否正确
static STRING_POOL: Lazy<Arc<Mutex<HashMap<String, usize>>>> = Lazy::new(|| Arc::new(Mutex::new(HashMap::new())));


fn put(key: String, val: *mut Object) {
    STRING_POOL.lock().unwrap().insert(key, val as usize);
}

pub fn get(key: &str) -> Option<*mut Object> {
    match STRING_POOL.lock().unwrap().get(key) {
        Some(val) => Some(unsafe { std::mem::transmute(*val) }),
        None => None
    }
}

pub fn contains_key(key: &str) -> bool {
    STRING_POOL.lock().unwrap().contains_key(key)
}

pub fn j_string(loader: &mut ClassLoader, key: &str) -> *mut Object {
    if contains_key(key) {
        return get(key).unwrap();
    }
    let charts = key.encode_utf16().collect::<Vec<u16>>();
    let j_charts = Object::new_object(loader.load_class("[C".to_string()), DataType::Array(super::ArrayObject::Char(charts)));
    let class = loader.load_class("java/lang/String".to_string());
    let j_str = Box::into_raw(Box::new(Class::new_object(class)));  
    unsafe { &mut *j_str }.set_ref_var("value", "[C", Box::into_raw(Box::new(j_charts)));
    put(key.to_string(), j_str);
    j_str
}

pub fn rs_string(j_str: *mut Object) -> String {
    let char_arr = unsafe { &*j_str }.get_ref_var("value", "[C");
    if let super::ArrayObject::Char(chars) = unsafe { &*char_arr.unwrap() }.get_array() {
        String::from_utf16(chars).unwrap()
    } else {
        panic!("")
    }
}

pub fn intern_string(j_str: *mut Object) -> *mut Object {
    let rs_str = rs_string(j_str);
    if contains_key(&rs_str) {
        return get(&rs_str).unwrap();
    }
    put(rs_str, j_str);
    j_str
}